﻿/// <summary>
/// ***************C#版SQL防注入程序 v1.0************
///
/// *使用方法：
/// 一、整站防注入(推荐)
/// 在Global.asax.cs中查找Application_BeginRequest函数加入代码，如下
/// protected void Application_BeginRequest(Object sender, EventArgs e)
///{
/// //防SQL注入代码
/// SqlInject myCheck = new SqlInject(this.Request);
/// myCheck.CheckSqlInject();
///}
/// 二、单独页面防注入
/// 在要保护的页面cs文件的Page_Load函数中加入代码，如下:
/// protected void Page_Load(object sender, EventArgs e)
/// {
/// SqlInject myCheck = new SqlInject(this.Request);
/// myCheck.CheckSqlInject();
/// }
/// 三、基本设置
/// 1.修改private const int _type = 3 的_type参数来设置Sql注入警告及日志记录方式；
/// 2.修改string errRedirectPage = "/err.aspx" 来设置自定义错误处理页面；
/// 3.如果_type=1或者3，那么请务必设置string errMDBpath = "/SqlInject.mdb"相应的日志数据库路径；
/// 4.如果采取默认程序，那么请将本程序对应的SqlInject.mdb放至网站系统根目录下。
/// 
/// *版权说明:
/// 一、部分代码参考Asp版Sql通用防注入程序3.2 Neeao站点：http://www.neeao.com ；
/// 二、大部分核心代码参考网上匿名.NET防注入代码，感谢！
/// 三、此代码可以到www.wbyj.com获取下载和更新,或者联系作者QQ319861020。
/// ***********************************
/// ***********************************
/// </summary>
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.OleDb;
using System.Text.RegularExpressions;
public class SqlInject : System.Web.UI.Page
{
    //检测到注入后的处理方式: 0:仅警告；1：警告+记录；2：警告+自定义错误页面；3：警告+记录+自定义错误页面
    private const int _type = 3;
    private const string errRedirectPage = "/err.aspx";
    //如果记录注入信息，那么请设置：errMDBpath：数据库路径
    private const string errMDBpath = "/SqlInject.mdb";


    //过滤特征字符
    private const string StrKeyWord = @"select|insert|delete|from|count(|drop table|update|truncate|asc(|mid(|char(|xp_cmdshell|exec|master|net local group administrators|net user|or|and";
    private const string StrRegex = @"-|;|,|/|(|)|[|]|{|}|%|@|*|'|!";
    private HttpRequest request;
    public SqlInject(System.Web.HttpRequest _request)
    {
        this.request = _request;
    }
    ///<summary>
    ///检测SQL注入及记录、显示出错信息
    ///</summary>
    public void CheckSqlInject()
    {
        bool isInject = false;
        if (CheckRequestQuery() || CheckRequestForm())
        {
            isInject = true;
        }
        else
        {
            return;
        }

        switch (_type)
        {
        case 0:
            ShowErr();
            break;
        case 1:
            ShowErr();
            SaveToMdb();
            break;
        case 2:
            ShowErr();
            string temp;
            System.Web.HttpContext.Current.Response.Write("<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>");
            break;
        case 3:
            ShowErr();
            SaveToMdb();
            System.Web.HttpContext.Current.Response.Write("<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>");
            break;
        default:
            break;
        }
        System.Web.HttpContext.Current.Response.End();

    }
    private void SaveToMdb()
    {
        OleDbConnection conn = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + Server.MapPath(errMDBpath));
        conn.Open();
        OleDbCommand cmd = conn.CreateCommand();

        cmd.CommandText = "insert into [Record] (sIP,sDate,sPath) values ('" +
                          request.ServerVariables["REMOTE_ADDR"].ToString() + "','" +
                          DateTime.Now + "','" + request.ServerVariables["URL"].ToLower() + RelaceSingleQuotes(request.QueryString.ToString()) + "')";
        int code = cmd.ExecuteNonQuery();
        if (code == 1)
            System.Web.HttpContext.Current.Response.Write("<br>****以上信息已记录至日志数据库****");
        else
            System.Web.HttpContext.Current.Response.Write("<br>日志数据库出错");
        conn.Close();

    }
    private string RelaceSingleQuotes(string _url)
    {
        string URL = _url.Replace("'", "单引号");
        return URL;
    }
    private void ShowErr()
    {
        string msg = @"<font color=red>请不要尝试未授权之入侵检测！</font>" + @"<br><br>";
        msg += @"操作IP：" + request.ServerVariables["REMOTE_ADDR"] + @"<br>";
        msg += @"操作时间：" + DateTime.Now + @"<br>";
        msg += @"页面：" + request.ServerVariables["URL"].ToLower() + request.QueryString.ToString() + @"<br>";
        msg += @"<a href='#' onclick='javascript:window.close()'>关闭</a>";
        System.Web.HttpContext.Current.Response.Clear();
        System.Web.HttpContext.Current.Response.Write(msg);
    }
    ///<summary>
    /// 特征字符
    ///</summary>
    public static string KeyWord
    {
        get {
            return StrKeyWord;
        }
    }
    ///<summary>
    /// 特征符号
    ///</summary>
    public static string RegexString
    {
        get {
            return StrRegex;
        }
    }
    ///<summary>
    ///检查字符串中是否包含Sql注入关键字
    /// <param name="_key">被检查的字符串</param>
    /// <returns>如果包含注入true;否则返回false</returns>
    ///</summary>
    private static bool CheckKeyWord(string _key)
    {
        string[] pattenString = StrKeyWord.Split('|');
        string[] pattenRegex = StrRegex.Split('|');
        foreach (string sqlParam in pattenString)
        {
            if (_key.Contains(sqlParam + " ") || _key.Contains(" " + sqlParam))
            {
                return true;
            }
        }
        foreach (string sqlParam in pattenRegex)
        {
            if (_key.Contains(sqlParam))
            {
                return true;
            }
        }
        return false;
    }
    ///<summary>
    ///检查URL中是否包含Sql注入
    /// <param name="_request">当前HttpRequest对象</param>
    /// <returns>如果包含注入true;否则返回false</returns>
    ///</summary>
    public bool CheckRequestQuery()
    {
        if (request.QueryString.Count > 0)
        {
            foreach (string sqlParam in this.request.QueryString)
            {
                if (sqlParam == "__VIEWSTATE") continue;
                if (sqlParam == "__EVENTVALIDATION") continue;
                if (CheckKeyWord(request.QueryString[sqlParam].ToLower()))
                {
                    return true;
                }
            }
        }
        return false;
    }
    ///<summary>
    ///检查提交的表单中是否包含Sql注入
    /// <param name="_request">当前HttpRequest对象</param>
    /// <returns>如果包含注入true;否则返回false</returns>
    ///</summary>
    public bool CheckRequestForm()
    {
        if (request.Form.Count > 0)
        {
            foreach (string sqlParam in this.request.Form)
            {
                if (sqlParam == "__VIEWSTATE") continue;
                if (sqlParam == "__EVENTVALIDATION") continue;
                if (CheckKeyWord(request.Form[sqlParam]))
                {
                    return true;
                }
            }
        }
        return false;
    }
}